package com.zc.mychart.chart;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.PointF;
import androidx.core.content.ContextCompat;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;

import com.github.mikephil.charting.charts.LineChart;
import com.github.mikephil.charting.components.AxisBase;
import com.github.mikephil.charting.components.LimitLine;
import com.github.mikephil.charting.components.XAxis;
import com.github.mikephil.charting.components.YAxis;
import com.github.mikephil.charting.data.Entry;
import com.github.mikephil.charting.data.LineData;
import com.github.mikephil.charting.data.LineDataSet;
import com.github.mikephil.charting.formatter.IAxisValueFormatter;
import com.github.mikephil.charting.highlight.Highlight;
import com.github.mikephil.charting.interfaces.datasets.IDataSet;
import com.github.mikephil.charting.interfaces.datasets.ILineDataSet;
import com.github.mikephil.charting.listener.BarLineChartTouchListener;
import com.zc.mychart.R;
import com.zc.mychart.model.EntryData;
import com.zc.mychart.model.GoodsAllBean;
import com.zc.mychart.model.KTimeType;
import com.zc.mychart.utils.ArithUtil;
import com.zc.mychart.utils.DecimalUtil;
import com.zc.mychart.utils.FormatUtil;

import java.util.ArrayList;
import java.util.List;

/**
 * Created by Administrator on 2018/2/28 0028.
 */

public class MyLineChart extends LineChart {
    private Context mContext;
    private MarkerViewX markerViewX;
    private MarkerViewLeftY markerViewLeftY;
    private MarkerViewRightY markerViewRightY;
    private List<Entry> mEntries = new ArrayList<>();
    private double OFFSET = 0.1;
    private double mDiff;
    private float mLastValidX;
    private float mLastValidY;
    private int MIN_VISIBLE_RANGE = 110;
    private int mLabelCount = 3;
    private int multiple = 5;

    private int bgColor;
    private int lineColor;
    private int avgColor;
    private int textColor;
    private int chartLineColor;
    private int chartFillColor;
    private int bgMarker;
    private int markerTextColor;
    public static KTimeType mKTimeType = KTimeType.MIN1;
    public static double mWeight = 1;
    private GoodsAllBean mGroupBean;

    private boolean isFirstInit;

    public MyLineChart(Context context) {
        super(context);
        mContext = context;
    }

    public MyLineChart(Context context, AttributeSet attrs) {
        super(context, attrs);
        mContext = context;
    }

    public MyLineChart(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        mContext = context;
    }

    @Override
    protected void init() {
        super.init();
        Log.e("art", "init");
        mXAxisRenderer = new MyXAxisRender(mViewPortHandler, mXAxis, mLeftAxisTransformer);
        mAxisRendererLeft = new MyYAxisRender(mViewPortHandler, mAxisLeft, mLeftAxisTransformer);
        mAxisRendererRight = new MyYAxisRender(mViewPortHandler, mAxisRight, mRightAxisTransformer);
        mChartTouchListener = new MyBarLineChartTouchListener(this, mViewPortHandler.getMatrixTouch(), 3f);
    }

    public void setLightBg() {
        lineColor = ContextCompat.getColor(mContext, R.color.mychart_gray_k_line);
        avgColor = ContextCompat.getColor(mContext, R.color.mychart_avg_line);
        bgColor = ContextCompat.getColor(mContext, R.color.mychart_white_background);
        textColor = ContextCompat.getColor(mContext, R.color.mychart_text_main);
        chartLineColor = ContextCompat.getColor(mContext, R.color.mychart_blue_line);
        chartFillColor = R.drawable.k_line_fill_blue;
        bgMarker = R.drawable.k_marker_border_gray;
        markerTextColor = ContextCompat.getColor(mContext, R.color.mychart_black);
        setColors();
    }

    public void setDarkBg() {
        initDarkbg();
        setColors();
    }

    private void initDarkbg() {
        lineColor = ContextCompat.getColor(mContext, R.color.mychart_k_line);
        avgColor = ContextCompat.getColor(mContext, R.color.mychart_avg_line);
        bgColor = ContextCompat.getColor(mContext, R.color.mychart_background);
        textColor = ContextCompat.getColor(mContext, R.color.mychart_white);
        chartLineColor = ContextCompat.getColor(mContext, R.color.mychart_bg_k_line);
        chartFillColor = R.drawable.k_line_fill;
        bgMarker = R.drawable.k_marker_border;
        markerTextColor = ContextCompat.getColor(mContext, R.color.mychart_text_gray);
    }

    private void setColors() {
        setBackgroundColor(bgColor);
        setBorderColor(lineColor);
        mXAxis.setGridColor(lineColor);
        mAxisLeft.setGridColor(lineColor);
        mXAxis.setTextColor(textColor);
        mAxisLeft.setTextColor(textColor);
        mAxisRight.setTextColor(textColor);
        paint.setColor(chartLineColor);
        paintShape.setColor(chartLineColor);
        paintShape.setAlpha(105);

        markerViewX.setMarkerBg(bgMarker, markerTextColor);
        markerViewLeftY.setMarkerBg(bgMarker, markerTextColor);
        markerViewRightY.setMarkerBg(bgMarker, markerTextColor);

        try {
            LineData data = getData();
            if (data == null || data.getDataSetCount() == 0)
                return;
            List<ILineDataSet> sets = data.getDataSets();
            LineDataSet validSet = (LineDataSet) sets.get(0);
            validSet.setColor(chartLineColor);
            validSet.setFillDrawable(ContextCompat.getDrawable(mContext, chartFillColor));
            invalidate();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public void initView() {
        Log.e("art", "initView");
        minValue = 2;
        resetNumber = 6;
        if (null == paint) {
            paint = new Paint();
            paint.setAntiAlias(true);
        }
        if (null == paintShape) {
            paintShape = new Paint();
            paintShape.setAntiAlias(true);
        }
        initDarkbg();
        setMinOffset(0f);
        setDrawBorders(true);
        setBorderColor(lineColor);
        setBorderWidth(0.5f);
        setScaleYEnabled(false);
        setNoDataText("");
//        float xChartMax = getXChartMax();
//        Description description = new Description();
//        description.setText("原料价格走势");
//        description.setTextSize(15f);
//        description.setTextColor(ContextCompat.getColor(mContext,R.color.tab_text_black_03_color));
//        description.setPosition(xChartMax/2,100);
//        setDescription(description);
        getDescription().setEnabled(false);
        setBackgroundColor(bgColor);
        setDragDecelerationFrictionCoef(0.95f);
        setDoubleTapToZoomEnabled(false);
        setPinchZoom(true);
        setDragEnabled(false);
        setScaleXEnabled(false);
        setScaleYEnabled(false);
        setAutoScaleMinMaxEnabled(true);
        markerViewX = new MarkerViewX(mContext, R.layout.view_marker);
        markerViewLeftY = new MarkerViewLeftY(mContext, R.layout.view_marker);
        markerViewRightY = new MarkerViewRightY(mContext, R.layout.view_marker);
        markerViewX.setChartView(this);
        markerViewLeftY.setChartView(this);
        markerViewRightY.setChartView(this);
        markerViewX.setMarkerBg(bgMarker, markerTextColor);
        markerViewLeftY.setMarkerBg(bgMarker, markerTextColor);
        markerViewRightY.setMarkerBg(bgMarker, markerTextColor);

        mXAxis.setTextSize(9f);
        mXAxis.setDrawAxisLine(false);
        mXAxis.setDrawGridLines(true);
        mXAxis.setGridColor(lineColor);
        mXAxis.setTextColor(textColor);
        mXAxis.setLabelCount(mLabelCount);
        mXAxis.setAvoidFirstLastClipping(true);
        mXAxis.setGranularityEnabled(true);
        mXAxis.setYOffset(10f);
        mXAxis.setPosition(XAxis.XAxisPosition.BOTTOM);
        mXAxis.setValueFormatter(new IAxisValueFormatter() {
            @Override
            public String getFormattedValue(float value, AxisBase axis) {
                try {
                    int i = (int) value;
                    if (i > -1 && i < mEntries.size()) {
                        EntryData data = (EntryData) mEntries.get((int) value).getData();
                        if (data != null) {
                            return data.time;
                        }
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
                return "";
            }
        });

        mAxisLeft.setDrawAxisLine(false);
        mAxisLeft.setDrawGridLines(true);
        mAxisLeft.setGridColor(lineColor);
        mAxisLeft.setTextColor(textColor);
        mAxisLeft.setLabelCount(mLabelCount, true);
        mAxisLeft.setPosition(YAxis.YAxisLabelPosition.INSIDE_CHART);
        mAxisLeft.setValueFormatter(new IAxisValueFormatter() {
            @Override
            public String getFormattedValue(float value, AxisBase axis) {
                return FormatUtil.formatDouble2(value);
            }
        });

        mAxisRight.setDrawAxisLine(false);
        mAxisRight.setDrawGridLines(false);
        mAxisRight.setTextColor(textColor);
        mAxisRight.setLabelCount(mLabelCount, true);
        mAxisRight.setPosition(YAxis.YAxisLabelPosition.INSIDE_CHART);
        mAxisRight.setValueFormatter(new IAxisValueFormatter() {
            @Override
            public String getFormattedValue(float value, AxisBase axis) {
                if (value == 0) {
                    return "0.00%";
                }
                return DecimalUtil.div(value, 1, 2) + "%";
            }

        });
        mLegend.setEnabled(false);
    }


    public void setLineData(List<Entry> entries, double close, double high, double low, KTimeType type, GoodsAllBean bean, boolean isTrack) {
        this.mGroupBean = bean;
        if (entries != null && entries.size() > 0) {
            setMinMax(close, high, low);
            mKTimeType = type;
            if (mKTimeType == KTimeType.MIN1) {
                MIN_VISIBLE_RANGE = entries.size();
                setScaleXEnabled(false);
            } else if (mKTimeType == KTimeType.MINI7) {
                MIN_VISIBLE_RANGE = 300;
                setScaleXEnabled(true);
            } else if (mKTimeType == KTimeType.MINI10) {
                MIN_VISIBLE_RANGE = 180;
                setScaleXEnabled(true);
            }
            setData(generateLineData(entries));
            resetTracking();
            calculateScale();
        } else {
            clear();
        }
    }

    public void setLineDataNoTracking(List<Entry> entries, double close, double high, double low) {
        if (entries != null && entries.size() > 0) {
            setMinMax(close, high, low);
            setData(generateLineData(entries));
            calculateInvalidate();
        } else {
            clear();
        }
    }

    public void calculateInvalidate() {
        this.invalidate();
//        calculateOffsets();
    }


    public void calculateScale() {
        int minVisible = MIN_VISIBLE_RANGE;
//        if (getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE) {
//            minVisible = MIN_VISIBLE_RANGE * 2;
//        }
        setVisibleXRangeMinimum(minVisible);
//        mXAxis.setGranularity(minVisible / 3);
        if (null != mGroupBean && (mGroupBean.pro_code.contains("CAD") || mGroupBean.pro_code.contains("S"))) {
            mXAxis.setGranularity(minVisible / 2);
        }else{
            mXAxis.setGranularity(minVisible / 3);
        }
        int defaultVisible = minVisible;
        Matrix save = new Matrix();
        save.setScale(getXRange() / defaultVisible, 1f);
        mViewPortHandler.refresh(save, this, false);
        calculateOffsets();
        if (mChartTouchListener instanceof BarLineChartTouchListener) {
            ((BarLineChartTouchListener) mChartTouchListener).stopDeceleration();//停止滑动，防止计算出的scale被computeScroll()覆盖
        }
        moveViewToX(mLastValidX - defaultVisible + 50);
    }

    private void setMinMax(double close, double high, double low) {
        if (close != 0 && high != 0 && low != 0) {
            double diff = Math.max(Math.abs(high - close), Math.abs(low - close));
//            if (diff > mDiff) {
            mDiff = diff;
            markerViewRightY.setMidValue(close);
            double max = close + diff + diff * OFFSET;
            double min = close - diff - diff * OFFSET;
            mAxisLeft.setAxisMaximum((float) max);
            mAxisLeft.setAxisMinimum((float) min);
            mAxisRight.setAxisMaximum((float) ((max - close) * 100 / close));
            mAxisRight.setAxisMinimum((float) ((min - close) * 100 / close));
//            }
        }
    }

    private LineData generateLineData(List<Entry> entries) {
        LineData data = new LineData();
        LineDataSet[] sets = generateLineDataSets(entries);
        LineDataSet validSet = sets[0];

        validSet.setColor(chartLineColor);
        validSet.setFillDrawable(ContextCompat.getDrawable(mContext, chartFillColor));
        validSet.setLineWidth(1f);
        validSet.setDrawFilled(true);
        validSet.setDrawCircles(false);
        validSet.setDrawCircleHole(false);
        validSet.setDrawValues(false);
        validSet.setHighlightEnabled(true);
        validSet.setHighLightColor(ContextCompat.getColor(mContext, R.color.mychart_high_light_line));
        validSet.setAxisDependency(YAxis.AxisDependency.LEFT);


        LineDataSet setCopy = sets[1];
        setCopy.setLineWidth(1f);
        setCopy.setDrawCircles(true);
        setCopy.setDrawCircleHole(false);  //空心圆
        setCopy.setCircleRadius(2f);
//        setCopy.setCircleHoleRadius(2f);
        setCopy.setCircleColor(chartLineColor);
//        setCopy.setCircleHoleColor(ContextCompat.getColor(mContext, R.color.mychart_background));
//        setCopy.setCircleColorHole(ContextCompat.getColor(mContext, R.color.mychart_background));
        setCopy.setDrawValues(false);
        setCopy.setHighlightEnabled(false);
        setCopy.setAxisDependency(YAxis.AxisDependency.LEFT);
        LineDataSet setEmpty = sets[2];
        //当其他的DataSet不为空时，setDrawValues(true)的空DataSet会引发脚标越界异常，mpchartlib库的问题
        setEmpty.setDrawValues(false);


        LineDataSet avgSet = sets[3];
        avgSet.setColor(avgColor);
//        validSet.setFillDrawable(ContextCompat.getDrawable(mContext, R.drawable.k_line_fill));
        avgSet.setLineWidth(1f);
        avgSet.setDrawFilled(false);
        avgSet.setDrawCircles(false);
        avgSet.setDrawCircleHole(false);
        avgSet.setDrawValues(false);
        avgSet.setHighlightEnabled(false);


        data.addDataSet(validSet);
        data.addDataSet(setCopy);
        data.addDataSet(setEmpty);

        if (mKTimeType == KTimeType.MIN1) {
            data.addDataSet(avgSet);
        }
        return data;
    }


    List<Entry> validEntries = new ArrayList<>();
    List<Entry> averageEntries = new ArrayList<>();
    List<Entry> emptyEntries = new ArrayList<>();
    List<Entry> copyCircleEntries = new ArrayList<>();
    List<Entry> disableEntries = new ArrayList<>();

    private void clearEntriesCache(){
        validEntries.clear();
        averageEntries.clear();
        emptyEntries.clear();
        copyCircleEntries.clear();
        disableEntries.clear();
    }

    private LineDataSet[] generateLineDataSets(List<Entry> entries) {
        float totalVaildValue = 0;
        int totalVaildNumber = 0;
        LineDataSet[] sets = new LineDataSet[4];
        clearEntriesCache();
        Entry entry;
        int validIndex = entries.size();
        for (int i = 0; i < entries.size(); i++) {
            entry = entries.get(i);
            if (entry != null) {
                if (entry.getY() != 0 && entry.getY() != Float.NaN) {
                    validEntries.add(entry);
                    validIndex = i;
                    totalVaildValue += entry.getY();
                    totalVaildNumber += 1;
                    float avgValue = (float) ArithUtil.div(totalVaildValue, totalVaildNumber);
                    averageEntries.add(new Entry(entry.getX(), avgValue, entry.getData()));
                } else if (i > validIndex) {
                    emptyEntries.add(new Entry(entry.getX(), Float.NaN));
                } else {
                    disableEntries.add(entry);
                }
            }
        }
        if (!validEntries.isEmpty()) {
            Entry lastValidEntry = validEntries.get(validEntries.size() - 1);
            copyCircleEntries.add(lastValidEntry);
            mLastValidX = lastValidEntry.getX();
            mLastValidY = lastValidEntry.getY();
//            addLimitLine(lastValidEntry.getY());
        }
        sets[0] = new LineDataSet(validEntries, "");
        sets[1] = new LineDataSet(copyCircleEntries, "");
        sets[2] = new LineDataSet(emptyEntries, "");
        sets[3] = new LineDataSet(averageEntries, "");
        entries.removeAll(disableEntries);
        mEntries.clear();
        mEntries.addAll(entries);
        return sets;
    }

    private void addLimitLine(float y) {
        mAxisRight.removeAllLimitLines();
        String value = (y == (int) y) ? (int) y + "" : y + "";
        LimitLine line = new LimitLine(y, value);
        line.setLineWidth(1f);
        line.setTextColor(ContextCompat.getColor(mContext, R.color.mychart_rose_red));
        line.setLineColor(ContextCompat.getColor(mContext, R.color.mychart_rose_red));
        line.enableDashedLine(10f, 10f, 0f);
        line.setLabelPosition(LimitLine.LimitLabelPosition.RIGHT_TOP);
        line.setTextSize(10f);
        mAxisRight.addLimitLine(line);
    }

    private float minValue = 8;
    private float nodeRadius = minValue;
    private float resetNumber = 18;
    private float oneTapRange = 0.1f;
    private float offset = 6f;
    private float x;
    private float y;
    private Canvas canvas;
    private Paint paint;
    private Paint paintShape;
    public boolean onPopPause;

    public void setOnPopPause(boolean isPause) {
        this.onPopPause = isPause;
    }


    private void drawNode() {
        if (null == paint) {
            paint = new Paint();
            paint.setColor(chartLineColor);
            paint.setAntiAlias(true);
        }
//        nodeRadius = nodeRadius + oneTapRange;
//        if (Math.round(nodeRadius) >= resetNumber) {
//            nodeRadius = minValue;
//        }
        canvas.drawCircle(x, y, minValue, paint);
//        canvas.drawCircle(x, y, nodeRadius, paintShape);
        invalidate();
    }

    @Override
    protected void drawMarkers(Canvas canvas) {
        super.drawMarkers(canvas);
        this.canvas = canvas;
//        if (!onPopPause) {
//            LineDataSet circleDataSet = (LineDataSet) getLineData().getDataSets().get(1);
//            for (Entry e : circleDataSet.getValues()) {
//                MPPointD p = this.getPixelForValues(e.getX(), e.getY(), YAxis.AxisDependency.LEFT);
//                this.x = (float) p.x;
//                this.y = (float) p.y;
//                drawNode();
//            }
//        }
        if (markerViewX == null || markerViewLeftY == null || markerViewRightY == null || !isDrawMarkersEnabled() || !valuesToHighlight())
            return;
        Highlight highlight = mIndicesToHighlight[0];
        IDataSet set = mData.getDataSetByIndex(highlight.getDataSetIndex());
        Entry e = mData.getEntryForHighlight(mIndicesToHighlight[0]);
        int entryIndex = set.getEntryIndex(e);
        if (e == null || entryIndex > set.getEntryCount() * mAnimator.getPhaseX())
            return;
        float[] pos = getMarkerPosition(highlight);
        if (!mViewPortHandler.isInBounds(pos[0], pos[1]))
            return;

        markerViewX.refreshContent(e, highlight);
        markerViewLeftY.refreshContent(e, highlight);
        markerViewRightY.refreshContent(e, highlight);

        markerViewX.draw(canvas, pos[0], pos[1]);
        markerViewLeftY.draw(canvas, pos[0], pos[1]);
        markerViewRightY.draw(canvas, pos[0], pos[1]);
    }


    PointF downPoint = new PointF();

    public boolean onTouchEvent(MotionEvent evt) {
        switch (evt.getAction()) {
            case MotionEvent.ACTION_DOWN:
                downPoint.x = evt.getX();
                downPoint.y = evt.getY();
                break;
            case MotionEvent.ACTION_MOVE:
                if (getScaleX() > 1 && Math.abs(evt.getX() - downPoint.x) > 2) {
                    getParent().requestDisallowInterceptTouchEvent(true);
                }
                break;
        }
        return super.onTouchEvent(evt);
    }

}
